package com.atguigu.gmall.list.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.item.client.ItemServiceClient;
import com.atguigu.gmall.list.ListApplication;
import com.atguigu.gmall.list.dao.GoodsDao;
import com.atguigu.gmall.list.service.ListService;
import com.atguigu.gmall.model.list.*;
import com.atguigu.gmall.model.product.BaseCategoryView;
import com.atguigu.gmall.model.product.BaseTrademark;
import com.atguigu.gmall.model.product.SkuAttrValue;
import com.atguigu.gmall.model.product.SkuInfo;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ListServiceImpl implements ListService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Autowired
    private GoodsDao goodsDao;

    @Autowired
    private ItemServiceClient productFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;
    //创建索引
    @Override
    public void upperGoods(Long skuId) {
        Goods goods = new Goods();
        //1：根据skuID查询SkuInfo信息
        SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
        goods.setId(skuInfo.getId());
        goods.setDefaultImg(skuInfo.getSkuDefaultImg());
        goods.setTitle(skuInfo.getSkuName());
        goods.setPrice(skuInfo.getPrice().doubleValue());
        goods.setCreateTime(new Date());
        //2:根据tmId 查询品牌相关数据
        BaseTrademark baseTrademark = productFeignClient.getBaseTrademark(skuInfo.getTmId());
        goods.setTmId(baseTrademark.getId());
        goods.setTmName(baseTrademark.getTmName());
        goods.setTmLogoUrl(baseTrademark.getLogoUrl());
        //3:根据category3Id查询分类视图
        BaseCategoryView baseCategoryView = productFeignClient.
                getBaseCategoryView(skuInfo.getCategory3Id());
        goods.setCategory1Id(baseCategoryView.getCategory1Id());
        goods.setCategory1Name(baseCategoryView.getCategory1Name());
        goods.setCategory2Id(baseCategoryView.getCategory2Id());
        goods.setCategory2Name(baseCategoryView.getCategory2Name());
        goods.setCategory3Id(baseCategoryView.getCategory3Id());
        goods.setCategory3Name(baseCategoryView.getCategory3Name());
        //4：根据skuId 查询 sku_attr_value   base_attr_info  base_attr_value
        List<SkuAttrValue> skuAttrValueList = productFeignClient.getSkuAttrValue(skuId);
        //private List<SearchAttr> attrs;//平台属性集合  Stream流 偷天换日
        List<SearchAttr> searchAttrList = skuAttrValueList.stream().map(skuAttrValue -> {
            SearchAttr searchAttr = new SearchAttr();
            searchAttr.setAttrId(skuAttrValue.getBaseAttrInfo().getId());
            searchAttr.setAttrName(skuAttrValue.getBaseAttrInfo().getAttrName());
            searchAttr.setAttrValue(skuAttrValue.getBaseAttrValue().getValueName());
            return searchAttr;
        }).collect(Collectors.toList());
        goods.setAttrs(searchAttrList);
        //保存索引库
        goodsDao.save(goods);
    }
    //删除索引
    @Override
    public void lowerGoods(Long skuId) {
        //官方删除方式
//        DeleteRequest deleteRequest=new DeleteRequest();
//        deleteRequest.index("goods");
//        deleteRequest.id(skuId.toString());
//        try {
//            restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
    //  spring es 的删除方式
        goodsDao.deleteById(skuId);
    }

    //添加热度
    @Override
    public void hotScore(Long skuId) {
        //通过缓存进行缓冲，set类型进行自增 add初始化，incrementScore为追加
        Double hotScore = redisTemplate.opsForZSet().incrementScore("hotScore", skuId, 1);
        //十次更新一次
        if(hotScore%10==0){
            Optional<Goods> byId = goodsDao.findById(skuId);
            Goods goods = byId.get();
            goods.setHotScore(hotScore.longValue());
            goodsDao.save(goods);
        }
    }

    //查询索引
    @Override
    public SearchResponseVo search(SearchParam searchParam) {
        SearchResponseVo vo=null;
        try {
            //构建搜素请求对象
            SearchRequest searchRequest=buildSearchRequest(searchParam);
            //es中查询,执行搜索，搜素响应
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //解析回响
            vo = parseSearchResponse(search);
            //数据分页部分
            vo.setPageNo(searchParam.getPageNo());
            vo.setPageSize(searchParam.getPageSize());
            vo.setTotalPages((vo.getTotal()+vo.getPageSize()-1)/vo.getPageSize());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return vo;
    }

    //解析结果
    private SearchResponseVo parseSearchResponse(SearchResponse search) {
        //结果对象
        SearchResponseVo searchResponseVo=new SearchResponseVo();
        //过去结果集
        SearchHits hits = search.getHits();
        //获取所有集合
        Map<String, Aggregation> stringAggregationMap = search.getAggregations().asMap();

        //解析平台属性聚合
        //向下强转 parsedNested 嵌套类型
        ParsedNested aggAttrs = (ParsedNested) stringAggregationMap.get("aggAttrs");
        //获取子类对象，转换为String类型
        ParsedLongTerms aggAttrId = aggAttrs.getAggregations().get("aggAttrId");
        List<SearchResponseAttrVo> attrsList=aggAttrId.getBuckets().stream().map(backet->{
            SearchResponseAttrVo searchResponseAttrVo = new SearchResponseAttrVo();
            searchResponseAttrVo.setAttrId(( Long.parseLong(backet.getKeyAsString())));
            //获取aggAttrName子类
            ParsedStringTerms aggAttrName = ((Terms.Bucket) backet).getAggregations().get("aggAttrName");
            searchResponseAttrVo.setAttrName(aggAttrName.getBuckets().get(0).getKeyAsString());
            //获取aggAttrValue子类
            ParsedStringTerms aggAttrValue = ((Terms.Bucket) backet).getAggregations().get("aggAttrValue");
            List<String> attrValueList=aggAttrValue.getBuckets().stream().map(Terms.Bucket::getKeyAsString).collect(Collectors.toList());
            searchResponseAttrVo.setAttrValueList(attrValueList);
            return searchResponseAttrVo;
        }).collect(Collectors.toList());
        //将平台属性添加到返回值中
        searchResponseVo.setAttrsList(attrsList);
        //通过 searchSourceBuilder.aggregation(AggregationBuilders.terms("aggTmId").field("tmId") 取值
        //向下强转
        ParsedLongTerms aggTmId = (ParsedLongTerms) stringAggregationMap.get("aggTmId");
        //聚合获取集合
        //解析品牌聚合
        List<SearchResponseTmVo> trademarkList =aggTmId.getBuckets().stream().map((bucket)->{
            SearchResponseTmVo searchResponseTmVo=new SearchResponseTmVo();
            //bucket.getKeyAsString()获取key 品牌id
            searchResponseTmVo.setTmId(Long.parseLong(bucket.getKeyAsString()));
            //获取名称 ParsedStringTerms解析字符串类型
            ParsedStringTerms aggTmName = bucket.getAggregations().get("aggTmName");
            //获取图片
            ParsedStringTerms aggTmLogoUrl = bucket.getAggregations().get("aggTmLogoUrl");
            //aggTmName.getBuckets()取出所有内容  .get(0)只有一个  .getKeyAsString()转换为字符
            searchResponseTmVo.setTmName(aggTmName.getBuckets().get(0).getKeyAsString());
            searchResponseTmVo.setTmLogoUrl(aggTmLogoUrl.getBuckets().get(0).getKeyAsString());
            return searchResponseTmVo;
        }).collect(Collectors.toList());
        searchResponseVo.setTrademarkList(trademarkList);

        //商品结果集
        SearchHit[] hits1 = hits.getHits();
        List<Goods> collect = Arrays.stream(hits1).map((hit) -> {
            Goods goods = JSONObject.parseObject(hit.getSourceAsString(), Goods.class);
            //添加高亮
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(null!=highlightFields&&highlightFields.size()>0){
                HighlightField title = highlightFields.get("title");
                if(title!=null){
                    Text[] fragments = title.fragments();
                    String s = fragments[0].toString();
                    goods.setTitle(s);
                }
            }

            //获取source JSON串
            return goods;
        }).collect(Collectors.toList());
        searchResponseVo.setGoodsList(collect);
        //总条数
        searchResponseVo.setTotal(hits.getTotalHits());
        return searchResponseVo;

    }

    private SearchRequest buildSearchRequest(SearchParam searchParam) {
        SearchRequest searchRequest=new SearchRequest("goods");//只负责请求,请求索引可以多个
        //构建条件对象
       SearchSourceBuilder searchSourceBuilder=new SearchSourceBuilder();
        //搜素全部new MatchAllQueryMapper QueryBuilders强大的工具类
        //searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        //多条件查询，组合查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //主要条件，must必要条件 请求参数中取值keyword
        String keyword = searchParam.getKeyword();
        if(!StringUtils.isEmpty(keyword)){
            //queryBuilders.matchQuery()条件查询
            boolQueryBuilder.must(QueryBuilders.matchQuery("title",keyword).operator(Operator.AND));//添加条件取并集
        }else {
            //queryBuilders.matchAllQuery()没有条件时查询全部
            boolQueryBuilder.must(QueryBuilders.matchAllQuery());
        }
        //品牌Id:品牌名称
        String trademark = searchParam.getTrademark();
        if(!StringUtils.isEmpty(trademark)){
            //将id 和名称进行切片
            String[] split = StringUtils.split(trademark, ":");
            boolQueryBuilder.filter(QueryBuilders.termQuery("tmId",split[0]));
        }
        //一级id查询
        Long category1Id=searchParam.getCategory1Id();
        if(category1Id!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category1Id",category1Id));
        }
        //二级id查询
        Long category2Id=searchParam.getCategory2Id();
        if(category2Id!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category2Id",category2Id));
        }
        //三级id查询
        Long category3Id=searchParam.getCategory3Id();
        if(category3Id!=null){
            boolQueryBuilder.filter(QueryBuilders.termQuery("category3Id",category3Id));
        }
        //平台属性 平台属性Id:平台属性value:平台属性名称
        String[] props = searchParam.getProps();
        if(props!=null&&props.length>0){
            //创建attrs boolQuery
            BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

            //多条件查询，组合查询
            BoolQueryBuilder attrsboolQueryBuilder = QueryBuilders.boolQuery();
            for (String prop : props) {
                //切片
                String[] split = prop.split(":");
                //创建attrs子类boolQuery
                BoolQueryBuilder query = QueryBuilders.boolQuery();
                query.must(QueryBuilders.termQuery("attrs.attrId",split[0]));
                query.must(QueryBuilders.termQuery("attrs.attrValue",split[1]));
                //嵌套查询，表查询,将子类聚合到attrs中

                boolQuery.must(QueryBuilders.nestedQuery("attrs",query, ScoreMode.None));
                //boolQuery.must(query);

            }
            //将attrs添加到多条件查询boolQueryBuilder中
            boolQueryBuilder.filter(boolQuery);
        }
        //条件添加完成
        //将boolQueryBuilder组合查询条件添加的查询条件中
        searchSourceBuilder.query(boolQueryBuilder);
        //构建查询条件 1:asc 1:desc 2:asc 2；desc
        String order = searchParam.getOrder();
        if(!StringUtils.isEmpty(order)){
            //切篇
            String[] split = StringUtils.split(order, ":");
            String orders=null;
            switch (split[0]){
                case "1":orders="hotScore";break;
                case "2":orders="price";break;
            }
            //排序，将前台需要的数据进行排序
            searchSourceBuilder.sort(orders,split[1].equalsIgnoreCase(SortOrder.ASC.toString())?SortOrder.ASC:SortOrder.DESC);
        }
        //进行分页处理
        Integer pageNo = searchParam.getPageNo();
        Integer pageSize = searchParam.getPageSize();
        searchSourceBuilder.from((pageNo-1)*pageSize);
        searchSourceBuilder.size(pageSize);

        //高亮
        //获取高亮对象
        HighlightBuilder builder = new HighlightBuilder();
        //选中高亮字段 添加前缀和后缀
        builder.field("title").preTags("<span style='color:blue'>").postTags("</span>");
        //向es查询中添加高亮
        searchSourceBuilder.highlighter(builder);

        //聚合 品牌聚合
        //aggregation聚合  group by 进行分组
        //AggregationBuilders.terms()精准聚合  field 那个域
        searchSourceBuilder.aggregation(AggregationBuilders.terms("aggTmId").field("tmId").size(80)
                .subAggregation(AggregationBuilders.terms("aggTmName").field("tmName").size(80))
                .subAggregation(AggregationBuilders.terms("aggTmLogoUrl").field("tmLogoUrl").size(80)));//subAggregation子聚合

        // 平台聚合 searchSourceBuilder.aggregation聚合
        searchSourceBuilder.aggregation(
                //nested嵌套
                AggregationBuilders.nested("aggAttrs","attrs")
                        .subAggregation(AggregationBuilders.terms("aggAttrId").field("attrs.attrId")
                        .subAggregation(AggregationBuilders.terms("aggAttrValue").field("attrs.attrValue"))
                        .subAggregation(AggregationBuilders.terms("aggAttrName").field("attrs.attrName"))));
        //单条件查询
        //searchSourceBuilder.query(QueryBuilders.matchQuery());
        //searchRequest.indices("goods");和new SearchRequest("goods");相同指向索引
        //searchRequest.types("info");mysql表， es只有一张表，7.4之后已经指定
        searchRequest.source(searchSourceBuilder);
        return searchRequest;
    }
}

